#ifndef ACCUMULSUPPORT_H_
#define ACCUMULSUPPORT_H_

#include <functional>
#include <sstream>
#include <iostream>

#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>

#define COLL_TO_STRING( coll ) accumf::iteraccumulate( coll.begin(), coll.end(), std::string(), accumf::ToStringAccumulator( coll.end() ) )
#define ARR_TO_STRING( arr, size ) accumf::iteraccumulate( arr, arr + size, std::string(), accumf::ToStringAccumulator( arr + size ) )
#define MATR_ARR_TO_STRING( matr, sizeN, sizeM ) accumf::matrArrToString( matr, sizeN, sizeM )

namespace accumf
{
	template < class F, class T >
	T memXOR( F src )
	{
		assert( sizeof( F ) > sizeof( T ) );
		int count = sizeof( F ) / sizeof( T );
		T result = 0;
		T * beg = reinterpret_cast< T * >( & src );
		for ( int i = 0; i < count; i++ ) {
			T & cur = * beg;
			result ^= cur;
			beg++;
		}
		return result;
	}

	template< class T >
	T inc( T * t )
	{
		( * t )++;
		return * t;
	}

	template< class T >
	void set( T & dest, const T & value )
	{
		dest = value;
	}

	template< class ColT, class T >
	void reinit( ColT & collection, int newSize, const T & value )
	{
		assert( newSize >= 0 );
		collection.resize( newSize );
		fill( collection.begin(), collection.end(), value );
	}

	class SmartToStringSupp
	{
	public:
		static const std::string EMPTY_STRING;
	};

	template< class IterT >
	class SmartToString
	{
	public:
		SmartToString( IterT end, const char * separator )
			: separator( separator )
			, buf( new std::stringstream() )
			, end( end )
			, isFirst( true )
		{
		}
		std::string operator () ( const std::string &, IterT b )
		{
			if ( b == end )
			{
				return buf->str();
			} else
			{
				if ( !isFirst )
				{
					( * buf ) << separator;
				}
				isFirst = false;
				( * buf ) << ( * b );
				return SmartToStringSupp::EMPTY_STRING;
			}
		}
	private:
		boost::shared_ptr< std::stringstream > buf;
		const char * separator;
		IterT end;
		bool isFirst;
	};

	template< class IterT >
	SmartToString< IterT > ToStringAccumulator( IterT end, const char * separator = ", " )
	{
		return SmartToString< IterT >( end, separator );
	}

	template< class Iter, class Result, class Functor >
	Result iteraccumulate( Iter beg, Iter end, Result init, Functor functor )
	{
		for ( ; beg != end; ++beg )
		{
			init = functor( init, beg );
		}
		init = functor( init, end );
		return init;
	}

	template< class T >
	std::string matrArrToString( T * * matr, int sizeN, int sizeM )
	{
		std::stringstream buf;
		for ( int i = 0; i < sizeN; i++ )
		{
			buf << ( const char * )( i == 0 ? "" : "\n" ) << ARR_TO_STRING( matr[i], sizeM );
		}
		return buf.str();
	}

	template< class CndTy, class ThnTp, class ElsTp >
	class IFFunctor
	{
	public:
		IFFunctor( CndTy c, ThnTp t, ElsTp e )
			: c( c ), t( t ), e( e )
		{
		}

		void operator() ( int a )
		{
			bool condHolds = c( a );
			if ( condHolds )
			{
				t( a );
			} else
			{
				e( a );
			}
		}

	private:
		CndTy c;
		ThnTp t;
		ElsTp e;
	};

	template< class CndTy, class ThnTp, class ElsTp >
	IFFunctor< CndTy, ThnTp, ElsTp > iftefnc( CndTy c, ThnTp t, ElsTp e )
	{
		return IFFunctor< CndTy, ThnTp, ElsTp >( c, t, e );
	}
}

class Fail
{
public:
	template< class T >
	static void fail( T line )
	{
		std::stringstream buf;
		buf << "assertion fail: " << line;
		std::cout << "\n\n" << buf.str();
		throw buf.str();
	}
};

#define dbgassert( expr ) if ( !( expr ) ) Fail::fail( __LINE__ );

#endif /* ACCUMULSUPPORT_H_ */
